home *** CD-ROM | disk | FTP | other *** search
- /* genebank.c 19-8-91 genebank manager for the tierra simulator */
- /** Tierra Simulator V3.0: Copyright (c) 1991 Thomas S. Ray **/
- /* rationale for genebank function are commented at the end of this file */
-
- #include "license.h"
-
- #ifndef lint
- static char sccsid[] = "@(#)genebank.c 2.5 8/27/91";
- #endif
-
- #include "tierra.h"
- #include "extern.h"
- #include <errno.h>
-
- void GetGenFileList() /* read list from disk, and set up list in memory */
- { I8s data[80]; /* when program starts up */
- I32s size, i, j, k, gi, ng, onum;
- FILE *inl;
- Psl tsl;
- Pgl sgl = (Pgl) thcalloc(1, sizeof(struct g_list));
-
- num_genq = 0;
- #ifdef IBM3090
- sprintf(data,"list.io.d");
- #else
- sprintf(data,"%slist", GenebankPath);
- #endif
- inl = fopen(data,"r");
- if (inl == NULL)
- { sprintf(mes[0],"GetGenFileList: file %s not opened, exiting", data);
- FEMessage(1);
- while(hangup) ;
- exit(0);
- }
- fgets(data,79,inl);
- sscanf(data,"NumSizes: %ld num_gentypes: %ld",&NumSiz,&num_gen);
- siz_sl = ((NumSiz / 20L) + 1L) * 20L + 20L;
- NumSizl = NumSiz;
- num_genl = num_gen;
- tsl = (Psl) thcalloc((I32u) siz_sl, (I32u) sizeof(struct s_list));
- if (tsl == NULL)
- { sprintf(mes[0],"Tierra GetGenFileList tsl thcalloc error");
- FEMessage(1);
- while(hangup) ;
- exit(0);
- }
- else sl = tsl;
- for (i = 0; i < NumSiz; i++) /* read list of sizes and # gens of each */
- { if (fgets(data,79,inl) == NULL) break;
- data[strlen(data) - 1] = 0;
- tsl = sl + i;
- sscanf(data,"%ld%ld", &tsl->size, &tsl->num);
- tsl->num_s = tsl->num;
- tsl->a_num = tsl->num + 20;
- tsl->g = (Pgl) thcalloc((I32u) tsl->a_num, sizeof(struct g_list));
- if (tsl->g == NULL)
- { sprintf(mes[0],"Tierra GetGenFileList sl.g thcalloc error");
- FEMessage(1);
- while(hangup) ;
- exit(0);
- }
- for (j=0; j < tsl->a_num; j++) InitGList(tsl->g + j, i, j, tsl->size);
- }
- for (i = 0; i < NumSiz; i++) /* read list of genotypes */
- { tsl = sl + i;
- ng = tsl->num;
- for (j = 0; j < ng; j++)
- { if (fgets(data,79,inl) == NULL) break;
- sscanf(data,"%ld%s%f%f%ld", &size, sgl->gen.label,
- &sgl->MaxPropPop, &sgl->MaxPropInst, &sgl->bits);
- #ifdef IBM3090
- Ebcdic2Ascii(sgl->gen.label);
- #endif
- gi = Lbl2Int(sgl->gen.label);
- sgl->b.si = sgl->a.si = i;
- sgl->b.gi = sgl->a.gi = gi;
- if (gi >= tsl->a_num)
- { onum = tsl->a_num;
- tsl->a_num = gi + 4;
- tsl->g = (Pgl) threalloc((I8s Hp) tsl->g,
- (I32u) sizeof(struct g_list) * tsl->a_num);
- for (k = onum; k < tsl->a_num; k++)
- InitGList(tsl->g + k, i, k, tsl->size);
- }
- sgl->gen.size = size;
- *(tsl->g + gi) = *sgl;
- }
- #ifdef ERROR
- if (size != tsl->size)
- { sprintf(mes[0],"Tierra GetGenFileList size match error");
- FEMessage(1);
- while(hangup) ;
- exit(0);
- }
- #endif
- }
- thfree(sgl);
- fclose(inl);
- }
-
- void InitGList(g, si, gi, size)
- Pgl g;
- I32s si, gi, size;
- {
- g->pop = 0;
- g->bits = 0;
- g->gen.label[0] = g->gen.label[1] = g->gen.label[2] = 45;
- g->gen.label[3] = 0; /* "---" */
- g->gen.size = size;
- g->parent.label[0] = g->parent.label[1] = g->parent.label[2] = 45;
- g->parent.label[3] = 0; /* "---" */
- g->parent.size = 0;
- g->d1.inst = g->d1.flags = g->d1.mov_daught = g->d1.BreedTrue = 0;
- g->d2.inst = g->d2.flags = g->d2.mov_daught = g->d2.BreedTrue = 0;
- g->originI.i = g->originI.m = g->originC = 0;
- g->MaxPropPop = g->MaxPropInst = 0;
- g->comments = NULL; g->genome = NULL, g->gbits = NULL;
- g->b.si = g->a.si = si;
- g->b.gi = g->a.gi = gi;
- }
-
- void find_gl(g,gli) /* find the list index of a certain genotype */
- struct genotype *g;
- struct gl_index *gli;
- {
- I32s i, j;
-
- for (i = 0; i < NumSizl; i++) if (g->size == (sl + i)->size) {
- for (j = 0; j < (sl + i)->num; j++)
- if (!strcmp(g->label,((sl + i)->g + j)->gen.label)) {
- gli->si = i; gli->gi = j;
- return ;
- }
- }
- sprintf(mes[0],"Tierra find_gl error");
- if (!hangup)
- FEMessage(1);
- else
- { sprintf(mes[1],"system being saved to disk");
- FEMessage(2);
- }
- while(hangup) ;
- WriteSoup(1);
- exit(0);
- }
-
- void CheckGenotype(ci,gli) /* check if ci is a new genotype */
- I32s ci;
- struct gl_index *gli;
- {
- IsNewSize(ci,gli);
- if (IsInGenQueue(ci,gli)) return ;
- if (IsInGenBank(ci,gli)) return ;
- NewGenotype(ci,gli); /* register new genotype in the lists */
- }
-
- void IsNewSize(ci,gli)
- I32s ci;
- struct gl_index *gli;
- {
- I32s i;
- Psl tsl;
- Pgl tgl;
-
- for (i = 0; i < NumSizl; i++)
- if ((sl + i)->size == (cells + ci)->mm.s) {
- gli->si = i;
- return ;
- }
- if (++NumSizl > siz_sl)
- { siz_sl += 20;
- tsl = (Psl) threalloc((I8s Hp) sl, sizeof(struct s_list) * siz_sl);
- if (tsl == NULL)
- { sprintf(mes[0],"Tierra IsNewSize threalloc error");
- if (!hangup)
- FEMessage(1);
- else
- { sprintf(mes[1],"system being saved to disk");
- FEMessage(2);
- }
- while(hangup) ;
- WriteSoup(1);
- exit(0);
- }
- else sl = tsl;
- sprintf(mes[0],"lgeneban: realloc, siz_sl = %ld", siz_sl);
- FEMessage(1);
- for (i = siz_sl - 20; i < siz_sl; i++)
- { tsl = sl + i;
- tsl->size = tsl->num = tsl->num_s = tsl->num_q = tsl->a_num = 0;
- tsl->g = NULL;
- }
- }
- (sl + NumSizl - 1)->size = (cells + ci)->mm.s;
- (sl + NumSizl - 1)->a_num = 20;
- tgl = (sl + NumSizl - 1)->g = (Pgl) thcalloc(20, sizeof(struct g_list));
- for (i = 0; i < 20; i++)
- InitGList(tgl + i, NumSizl - 1, i, (cells + ci)->mm.s);
- gli->si = NumSizl - 1;
- return ;
- }
-
- I8s IsInGenQueue(ci,gli)
- I32s ci;
- struct gl_index *gli;
- {
- Pcells ce = cells + ci;
- I32s i;
- Pgl tgl;
- Psl tsl;
-
- tsl = sl + gli->si;
- for (i = 0; i < tsl->num; i++)
- { tgl = tsl->g + i;
- if (tgl->genome != NULL &&
- IsSameGen(ce->mm.s,(HpInst)(soup + ce->mm.p),tgl->genome))
- { gli->gi = i;
- ce->d.gli = *gli;
- strcpy(ce->d.gen.label,tgl->gen.label);
- MovToTopGenQueue(gli);
- return 1;
- }
- }
- return 0;
- }
-
- I8s IsInGenBank(ci,gli) /* check to see if ci is in the disk genebank */
- I32s ci;
- struct gl_index *gli;
- {
- Pcells ce = cells + ci;
- I32s i, j;
- I8s gfile[80];
- Psl tsl = (sl + gli->si);
- Pgl tgl, g = 0;
- FILE *afp;
- head_t head;
- indx_t *indx;
-
- #ifdef IBM3090
- sprintf(gfile,"%04ld.gen.d", tsl->size);
- #else
- sprintf(gfile,"%s%04ld.gen", GenebankPath, tsl->size);
- #endif
-
- if (!(afp = fopen(gfile, "rb")))
- { if (errno == ENOENT) return 0;
- perror("IsInGenBank");
- exit(9);
- }
- head = read_head(afp);
-
- /*
- head.magic[3] = '1';
- */
-
- if (strncmp(head.magic, "tie", 3) || head.magic[3] - '0' != INST)
- { fprintf(stderr, "IsInGenBank: bad magic number");
- exit(10);
- }
- indx = read_indx(afp, &head);
-
- for (i=0; i<tsl->num; i++) /* read all gens of this size from disk */
- { tgl = tsl->g + i; /* tgl = the ith genotype of this size */
- if (tgl->genome == NULL && (IsBit(tgl->bits,0) || tgl->pop > 0))
- /* check only genotypes that are not in RAM bank, but which */
- /* have been saved to disk (either permanent or temporary names) */
-
- { if ((j = find_gen(indx, tgl->gen.label, head.n)) == head.n)
- { fprintf(stderr, "%s not in archive\n", tgl->gen.label);
- continue;
- }
- g = get_gen(afp, &head, &indx[j], j);
-
- if (IsSameGen(ce->mm.s, (HpInst) (soup + ce->mm.p), g->genome))
- /* if disk genotype matches soup genotype */
- /* name cell and put genotype in genequeue */
- { strcpy(ce->d.gen.label,tgl->gen.label);
- ce->d.gli.si = gli->si; ce->d.gli.gi = gli->gi = i;
- *tgl = *g;
- AddTopGenQueue(gli); /* define gli.gi, and place in queue */
- thfree(g);
- fclose(afp);
- return 1;
- }
- else if (!RamBankSiz || num_genq < RamBankSiz)
- { gli->gi = i;
- *tgl = *g;
- AddTopGenQueue(gli);
- }
- else if (g->genome)
- { thfree(g->genome);
- g->genome = NULL;
- }
- if (g) thfree(g);
- }
- }
- thfree(indx);
- fclose(afp);
- return 0;
- }
-
- void NewGenotype(ci,gli) /* add a new genotype to the RAM list */
- I32s ci;
- struct gl_index *gli;
- {
- Pcells ce = cells + ci;
- Psl tsl = (sl + gli->si); /* point to this size in size list */
- Pgl tgl;
- I32s i, j;
- I8s found = 0;
-
- for (i = 0; i < tsl->num; i++) /* find a free name if there is one */
- { tgl = tsl->g + i;
- if (!IsBit(tgl->bits,0) && tgl->pop < 1)
- { gli->gi = i;
- found = 1;
- break;
- }
- }
- if (!found) AddToGl(gli); /* if no free name, make a new one */
- tgl = tsl->g + gli->gi; /* point to this new genotype */
- strcpy(ce->d.gen.label,tgl->gen.label);
- tgl->d1.inst = tgl->d1.flags = tgl->d1.mov_daught = tgl->d1.BreedTrue = 0;
- tgl->d2.inst = tgl->d2.flags = tgl->d2.mov_daught = tgl->d2.BreedTrue = 0;
- if (tgl->genome == NULL)
- { AddTopGenQueue(gli);
- tgl->genome = (HpInst) thcalloc(tsl->size, sizeof(Instruction));
- if (tgl->genome == NULL)
- { sprintf(mes[0],"Tierra NewGenotype thcalloc error 1");
- if (!hangup)
- FEMessage(1);
- else
- { sprintf(mes[1],"system being saved to disk");
- FEMessage(2);
- }
- while(hangup) ;
- WriteSoup(1);
- exit(0);
- }
- }
- if (tgl->gbits == NULL)
- { tgl->gbits = (HpGenB) thcalloc(tsl->size, sizeof(GenBits));
- if (tgl->gbits == NULL)
- { sprintf(mes[0],"Tierra NewGenotype thcalloc error 2");
- if (!hangup)
- FEMessage(1);
- else
- { sprintf(mes[1],"system being saved to disk");
- FEMessage(2);
- }
- while(hangup) ;
- WriteSoup(1);
- exit(0);
- }
- }
- else if (!found) AddTopGenQueue(gli);
- else MovToTopGenQueue(gli);
- for (i = 0; i < tsl->size; i++)
- { for (j = 0; j < PLOIDY; j++)
- { tgl->genome[i][j] = soup[ad(ce->mm.p + i)][j];
- }
- }
- tgl->originC = time(NULL);
- tgl->originI = InstExe;
- tgl->parent = ce->d.parent;
- tgl->bits = 0; tgl->pop = 0;
- if (reaped)
- { tgl->MaxPropPop = (float) 1 / (float) NumCells;
- tgl->MaxPropInst = (float) tsl->size / (float) SoupSize;
- }
- tgl->ploidy = ce->d.ploidy;
- tgl->track = ce->c.tr;
- }
-
- I32u WhoIs(ci, a)
- I32s *ci;
- Ind a;
- {
- Pcells ce = cells + *ci;
- I8s md;
-
- if (a >= ce->mm.p && a < ce->mm.p + ce->mm.s) return 0; /* same cell */
- if (a >= ce->md.p && a < ce->md.p + ce->md.s) return 1;/* daughter cell */
- if (IsFree(a)) return 3; /* is free memory */
- WhichCell(a, ci, &md);
- if (md == 'm') return 2; /* is other cell */
- return 4; /* is the daughter of another cell */
- }
-
- void AddToGl(gli)
- struct gl_index *gli;
- {
- I32s i;
- Psl tsl = sl + gli->si;
- Pgl tgl;
- I8s aaalabel[4];
-
- aaalabel[0] = aaalabel[1] = aaalabel[2] = 97;
- aaalabel[3] = 0;
- num_genl++;
- if (++tsl->num >= tsl->a_num) {
- tsl->a_num += 20;
- tsl->g = (Pgl) threalloc((I8s Hp) tsl->g,
- sizeof(struct g_list) * tsl->a_num);
- for (i = tsl->a_num - 20; i < tsl->a_num; i++)
- InitGList(tsl->g + i,gli->si,i,tsl->size);
- }
- tgl = tsl->g + tsl->num - 1;
- gli->gi = tsl->num - 1;
- if (tsl->num == 1) strcpy(tgl->gen.label,aaalabel);
- else IncrLbl(tgl->gen.label,(tgl - 1)->gen.label);
- if (reaped) {
- tgl->MaxPropPop = (float) 1 / (float) NumCells;
- tgl->MaxPropInst = (float) tsl->size / (float) SoupSize;
- }
- }
-
- I8s IsSameGen(size, g1, g2) /* compare two genomes */
- I32s size;
- HpInst g1, g2;
- {
- I32s i, j;
-
- for (i = 0; i < size; i++)
- { for (j = 0; j < PLOIDY; j++)
- if ((g1 + i)[j]->inst != (g2 + i)[j]->inst) return 0;
- }
- return 1;
- }
-
- void AddTopGenQueue(gli)
- struct gl_index *gli;
- {
- Pgl tgl;
- Psl tsl;
-
- tsl = sl + gli->si;
- tgl = tsl->g + gli->gi;
- tsl->num_q++;
- if (!num_genq) gq_top = gq_bot = *gli;
- if(++num_genq > RamBankSiz) DelBotGenQueue();/* free place for genotype */
- tgl->b = gq_top; /* new top points below to old top of queue */
- ((sl+gq_top.si)->g+gq_top.gi)->a= *gli;/*old top points above to new top*/
- tgl->a = *gli; /* new top points above to self */
- gq_top = *gli; /* gli is now the top */
- }
-
- void MovToTopGenQueue(gli)
- struct gl_index *gli;
- {
- Pgl tgl;
-
- tgl = (sl + gli->si)->g + gli->gi;
- if (gli->si == gq_top.si && gli->gi == gq_top.gi) return ;
- if (gli->si == gq_bot.si && gli->gi == gq_bot.gi) {
- gq_bot = tgl->a; /* new bot is above old bot */
- ((sl + gq_bot.si)->g + gq_bot.gi)->b = gq_bot; /* new bot points */
- } /* down to self */
- else { /* next gq points to previous gq */
- ((sl + tgl->b.si)->g + tgl->b.gi)->a = tgl->a;
- ((sl + tgl->a.si)->g + tgl->a.gi)->b = tgl->b;
- } /* previous gq points to next gq */
- tgl->a = *gli; /* points up to self, is at top of queue */
- tgl->b = gq_top; /* points down to old top */
- ((sl+gq_top.si)->g + gq_top.gi)->a = *gli;/*old top points up to new top*/
- gq_top = *gli; /* gq_top is now gli */
- }
-
- void DelBotGenQueue()
- { struct gl_index new_gq_bot;
- Pgl ogl, ngl;
- Psl tsl;
- I8s path[80];
- FILE *fp;
- head_t head;
- indx_t *indx;
-
- tsl = sl + gq_bot.si;
- ogl = (sl + gq_bot.si)->g + gq_bot.gi; /* old bottom gl */
- if (ogl->pop > 0 && !IsBit(ogl->bits,0) && ogl->genome != NULL) {
- #ifdef IBM3090
- sprintf(path,"%04ld.tmp.d", tsl->size);
- #else
- sprintf(path,"%s%04ld.tmp", GenebankPath, tsl->size);
- #endif
- fp = open_ar(path, tsl->size, INST, 0);
- head = read_head(fp);
- indx = read_indx(fp, &head);
- add_gen(fp, &head, &indx, ogl);
- fclose(fp);
- }
- new_gq_bot = ogl->a;
- ngl = (sl + new_gq_bot.si)->g + new_gq_bot.gi; /* new bottom gl */
- ngl->b = new_gq_bot; /* new bottom gl points down to self */
- if (ogl->genome) {
- thfree(ogl->genome);
- ogl->genome = NULL;
- }
- num_genq--;
- tsl->num_q--;
- ogl->a = ogl->b = gq_bot;
- gq_bot = new_gq_bot;
- }
-
- void IncrLbl(lbln, lblo)
- I8s *lbln, *lblo; /* 97 = a, 122 = z in ASCII */
- {
- strcpy(lbln,lblo);
- if (lbln[2] < 122) {
- lbln[2]++;
- goto finish;
- }
- if (lbln[1] < 122) {
- lbln[1]++;
- lbln[2] = 97;
- goto finish;
- }
- if (lbln[0] < 122) {
- lbln[0]++;
- lbln[1] = 97;
- lbln[2] = 97;
- goto finish;
- }
- finish:
- return ;
- }
-
- void MaxLbl(lbl, s) /* if s > lbl then lbl = s */
- I8s *lbl, *s; /* 97 = a, 122 = z in ASCII */
- {
- if (strcmp(lbl,s) > 0) goto finish;
- if (strcmp(lbl,s) < 0) strcpy(lbl,s);
- if (lbl[2] < 122) {
- lbl[2]++;
- goto finish;
- }
- if (lbl[1] < 122) {
- lbl[1]++;
- lbl[2] = 97;
- goto finish;
- }
- if (lbl[0] < 122) {
- lbl[0]++;
- lbl[1] = 97;
- lbl[2] = 97;
- goto finish;
- }
- finish:
- return ;
- }
-
- I32s Lbl2Int(s)
- I8s *s;
- { if(s[0] == '-') return -1;
- return (s[2]- 'a') + (26 * (s[1] - 'a')) + (676 * (s[0] - 'a'));
- }
-
- void Int2Lbl(i, s)
- I32s i;
- I8s *s;
- { if(i < 0)
- { strcpy(s,"---");
- return;
- }
- s[0] = 'a' + i / 676;
- i %= 676;
- s[1] = 'a' + i / 26;
- i %= 26;
- s[2] = 'a' + i;
- s[3] = 0;
- }
-
- void DelGenFile(tgl) /* this fn is going away real soon */
- Pgl tgl;
- {
- I8s comd[99];
-
- #ifdef IBM3090
- strcpy(label, tgl->gen.label);
- Ascii2Ebcdic(label);
- sprintf(comd,"erase %04ld%s gen d", tgl->gen.size, label);
- #endif
- #ifdef unix
- sprintf(comd,"rm %s%04ld%c%04ld%s", GenebankPath,
- tgl->gen.size, SLASH, tgl->gen.size, tgl->gen.label);
- #endif
- #if __TURBOC__ || OS2_MC
- sprintf(comd,"del %s%04ld%c%04ld%s", GenebankPath,
- tgl->gen.size, SLASH, tgl->gen.size, tgl->gen.label);
- #endif
- system(comd);
- SetBit(&tgl->bits, 1, 0);
- }
-
- /* rationale for the functioning of the genebank:
-
- The term ``rambank'' refers to a collection of genotypes maintained in RAM
- The term ``diskbank'' refers to a collection of genotypes maintained on disk
- The term ``genebank'' refers to both the rambank and the diskbank
-
- Genotype names have two parts: size-label, for example 0080aaa, 0045eat,
- 6666god.
-
- 1) When a creature is born its genotype will be compared to that of its
- parent.
- A) if they are the same, the daughter will be given the same name as the
- mother.
- B) if they are not the same, the genebank will be searched.
- a) if the daughter genotype is found in the genebank, it will be given
- the same name as the genotype that it matches in the bank.
- b) if the daughter genotype does not match any genotype in the bank,
- a new name will be created for it, and it will be entered into the
- rambank.
- 2) For each birth and death a count of the population of both the genotype
- and the size class involved will be incremente or decremented, so that we
- have a count of the current population of each genotype and each size
- class. This information is maintained in rambank.
- 3) If a genotype frequency crosses a critical threshold, the genotype name
- will become permanent and the genotype will be saved to the diskbank.
- There may be several types of thresholds: proportion of population
- (e.g., 2%), proportion of soup, or just numbers of creatures.
- 4) When a genotype frequency drops to zero:
- A) If the genotype never crossed the thresholds, the genotype will be
- removed from the genebank, and its unique name will become available for
- reuse.
- B) If the genotype crossed the threshold, gaining a permanent name, it
- should be retained in the genebank.
- 5) Periodically, Tierra saves the complete state of the machine (e.g., every
- 100 million instructions executed). At that time, the complete rambank
- is saved to the diskbank. For this reason, 4 A applies also to genotypes
- which never became permanent, and these must be removed from the diskbank
- as well. The bitfield in the genotype structure tells us if a genotype is
- saved to the diskbank, and if it is permanent.
- 6) If the rambank becomes ``too full'', some relatively unused portion of it
- should be swapped to the diskbank. In DOS, ``too full'' could be signaled
- by a malloc failure. In unix, ``too full'' could be signaled by some
- specified limit on how big the rambank should get, if this seems wise.
- That portion of the rambank to be swapped to the diskbank might consist of
- the least recently accessed size class. For this reason it might be
- worthwhile to maintain a queue of size classes, ordered by last use.
- */
-